#include "cron_parser.h"
#include "logger.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// 月份名称映射
static const char *month_names[] = {
    "jan", "feb", "mar", "apr", "may", "jun",
    "jul", "aug", "sep", "oct", "nov", "dec", NULL
};

// 星期名称映射
static const char *weekday_names[] = {
    "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL
};

// 解析单个字段
int cron_field_to_int(const char *field, int min, int max, int *values, int *count) {
    if (!field || !values || !count) {
        return ERROR_INVALID_PARAM;
    }

    char *field_copy = strdup(field);
    if (!field_copy) {
        return ERROR_MEMORY_ALLOC;
    }

    char *token;
    char *saveptr = NULL;
    *count = 0;

    // 转换为小写
    for (char *p = field_copy; *p; p++) {
        *p = tolower(*p);
    }

    token = strtok_r(field_copy, ",", &saveptr);
    while (token) {
        // 处理通配符
        if (strcmp(token, "*") == 0) {
            for (int i = min; i <= max; i++) {
                if (*count < 60) { // 假设最大60个值
                    values[(*count)++] = i;
                }
            }
            token = strtok_r(NULL, ",", &saveptr);
            continue;
        }

        // 处理步长表达式 */5
        if (strncmp(token, "*/", 2) == 0) {
            int step = atoi(token + 2);
            if (step > 0) {
                for (int i = min; i <= max; i += step) {
                    if (*count < 60) {
                        values[(*count)++] = i;
                    }
                }
            }
            token = strtok_r(NULL, ",", &saveptr);
            continue;
        }

        // 处理范围表达式 1-5
        char *dash = strchr(token, '-');
        if (dash) {
            *dash = '\0';
            int start = atoi(token);
            int end = atoi(dash + 1);
            
            // 处理月份名称
            if (min == 1 && max == 12) {
                for (int i = 0; month_names[i]; i++) {
                    if (strcmp(token, month_names[i]) == 0) {
                        start = i + 1;
                    }
                    if (strcmp(dash + 1, month_names[i]) == 0) {
                        end = i + 1;
                    }
                }
            }
            
            // 处理星期名称
            if (min == 0 && max == 7) {
                for (int i = 0; weekday_names[i]; i++) {
                    if (strcmp(token, weekday_names[i]) == 0) {
                        start = i;
                    }
                    if (strcmp(dash + 1, weekday_names[i]) == 0) {
                        end = i;
                    }
                }
            }
            
            if (start >= min && end <= max && start <= end) {
                for (int i = start; i <= end; i++) {
                    if (*count < 60) {
                        values[(*count)++] = i;
                    }
                }
            }
            token = strtok_r(NULL, ",", &saveptr);
            continue;
        }

        // 处理单个值
        int value = atoi(token);
        
        // 处理月份名称
        if (min == 1 && max == 12) {
            for (int i = 0; month_names[i]; i++) {
                if (strcmp(token, month_names[i]) == 0) {
                    value = i + 1;
                    break;
                }
            }
        }
        
        // 处理星期名称
        if (min == 0 && max == 7) {
            for (int i = 0; weekday_names[i]; i++) {
                if (strcmp(token, weekday_names[i]) == 0) {
                    value = i;
                    break;
                }
            }
        }
        
        if (value >= min && value <= max) {
            if (*count < 60) {
                values[(*count)++] = value;
            }
        }
        
        token = strtok_r(NULL, ",", &saveptr);
    }

    free(field_copy);
    return SUCCESS;
}

cron_expr_t *cron_parse(const char *expression) {
    if (!expression) {
        return NULL;
    }

    cron_expr_t *expr = calloc(1, sizeof(cron_expr_t));
    if (!expr) {
        return NULL;
    }

    expr->original_expr = strdup(expression);
    expr->timezone = strdup("UTC"); // 默认时区

    // 分割cron表达式字段
    char *expr_copy = strdup(expression);
    if (!expr_copy) {
        cron_free(expr);
        return NULL;
    }

    char *fields[CRON_FIELD_COUNT] = {0};
    int field_count = 0;
    
    char *token = strtok(expr_copy, " \t");
    while (token && field_count < CRON_FIELD_COUNT) {
        fields[field_count++] = token;
        token = strtok(NULL, " \t");
    }

    free(expr_copy);

    // 标准cron表达式有5或6个字段
    if (field_count < 5 || field_count > 7) {
        LOG_ERROR("Invalid cron expression: %s (expected 5-7 fields, got %d)", 
                 expression, field_count);
        cron_free(expr);
        return NULL;
    }

    // 解析各个字段
    int field_index = 0;
    
    // 秒字段（可选）
    if (field_count == 6 || field_count == 7) {
        int count = 0;
        if (cron_field_to_int(fields[field_index], 0, 59, expr->seconds, &count) != SUCCESS) {
            LOG_ERROR("Failed to parse seconds field: %s", fields[field_index]);
            cron_free(expr);
            return NULL;
        }
        field_index++;
    } else {
        // 默认每秒
        expr->seconds[0] = 0;
    }

    // 分钟字段
    int count = 0;
    if (cron_field_to_int(fields[field_index], 0, 59, expr->minutes, &count) != SUCCESS) {
        LOG_ERROR("Failed to parse minutes field: %s", fields[field_index]);
        cron_free(expr);
        return NULL;
    }
    field_index++;

    // 小时字段
    count = 0;
    if (cron_field_to_int(fields[field_index], 0, 23, expr->hours, &count) != SUCCESS) {
        LOG_ERROR("Failed to parse hours field: %s", fields[field_index]);
        cron_free(expr);
        return NULL;
    }
    field_index++;

    // 日期字段
    count = 0;
    if (cron_field_to_int(fields[field_index], 1, 31, expr->days, &count) != SUCCESS) {
        LOG_ERROR("Failed to parse days field: %s", fields[field_index]);
        cron_free(expr);
        return NULL;
    }
    field_index++;

    // 月份字段
    count = 0;
    if (cron_field_to_int(fields[field_index], 1, 12, expr->months, &count) != SUCCESS) {
        LOG_ERROR("Failed to parse months field: %s", fields[field_index]);
        cron_free(expr);
        return NULL;
    }
    field_index++;

    // 星期字段
    count = 0;
    if (cron_field_to_int(fields[field_index], 0, 7, expr->weekdays, &count) != SUCCESS) {
        LOG_ERROR("Failed to parse weekdays field: %s", fields[field_index]);
        cron_free(expr);
        return NULL;
    }
    field_index++;

    // 年份字段（可选）
    if (field_index < field_count) {
        count = 0;
        // 简化处理：只支持1970-2069
        if (cron_field_to_int(fields[field_index], 1970, 2069, expr->years, &count) != SUCCESS) {
            LOG_WARN("Failed to parse years field: %s, using default", fields[field_index]);
            // 使用默认年份
            expr->years[0] = 1970;
        }
    } else {
        // 默认所有年份
        expr->years[0] = 1970;
    }

    return expr;
}

void cron_free(cron_expr_t *expr) {
    if (!expr) {
        return;
    }

    if (expr->original_expr) free(expr->original_expr);
    if (expr->timezone) free(expr->timezone);
    free(expr);
}

// 检查数组中是否包含某个值
static bool array_contains(int *array, int size, int value) {
    for (int i = 0; i < size; i++) {
        if (array[i] == value) {
            return true;
        }
    }
    return false;
}

bool cron_check_time(cron_expr_t *expr, time_t time) {
    if (!expr) {
        return false;
    }

    struct tm *tm_info = localtime(&time);
    if (!tm_info) {
        return false;
    }

    int second = tm_info->tm_sec;
    int minute = tm_info->tm_min;
    int hour = tm_info->tm_hour;
    int day = tm_info->tm_mday;
    int month = tm_info->tm_mon + 1; // tm_mon: 0-11
    int year = tm_info->tm_year + 1900;
    int weekday = tm_info->tm_wday; // tm_wday: 0-6, 0=Sunday

    // 检查秒
    if (!array_contains(expr->seconds, 60, second)) {
        return false;
    }

    // 检查分钟
    if (!array_contains(expr->minutes, 60, minute)) {
        return false;
    }

    // 检查小时
    if (!array_contains(expr->hours, 24, hour)) {
        return false;
    }

    // 检查日期
    if (!array_contains(expr->days, 32, day)) {
        return false;
    }

    // 检查月份
    if (!array_contains(expr->months, 13, month)) {
        return false;
    }

    // 检查星期
    if (!array_contains(expr->weekdays, 8, weekday) && 
        !array_contains(expr->weekdays, 8, 7) && weekday == 0) { // 7也表示周日
        return false;
    }

    // 检查年份
    if (!array_contains(expr->years, 100, year)) {
        return false;
    }

    return true;
}

time_t cron_next_time(cron_expr_t *expr, time_t after) {
    if (!expr) {
        return 0;
    }

    // 从after+1秒开始检查
    time_t current = after + 1;
    
    // 最多检查10年，避免无限循环
    time_t max_time = after + 10 * 365 * 24 * 3600;
    
    while (current <= max_time) {
        if (cron_check_time(expr, current)) {
            return current;
        }
        current++;
    }
    
    return 0; // 没有找到下一个时间
}

time_t cron_prev_time(cron_expr_t *expr, time_t before) {
    if (!expr) {
        return 0;
    }

    // 从before-1秒开始检查
    time_t current = before - 1;
    
    // 最多检查10年，避免无限循环
    time_t min_time = before - 10 * 365 * 24 * 3600;
    
    while (current >= min_time) {
        if (cron_check_time(expr, current)) {
            return current;
        }
        current--;
    }
    
    return 0; // 没有找到上一个时间
}

cron_result_t cron_check(cron_expr_t *expr, time_t time) {
    cron_result_t result = {0};
    
    if (!expr) {
        return result;
    }

    result.matches = cron_check_time(expr, time);
    if (result.matches) {
        result.prev_time = cron_prev_time(expr, time);
        result.next_time = cron_next_time(expr, time);
    } else {
        result.prev_time = cron_prev_time(expr, time);
        result.next_time = cron_next_time(expr, time);
    }
    
    return result;
}
